#ifndef PRVP_EVALUATORPRV_HPP_
#define PRVP_EVALUATORPRV_HPP_

//#include <cmath>
#include <stdlib.h>
#include <math.h>

#include "../OptFrame/Evaluation.hpp"
#include "../OptFrame/Evaluator.hpp"

#include "Representation.h"
#include "Memory.h"
#include "Solution.h"
#include "EvaluationPRV.h"

#include "ProblemInstance.hpp"

#define EPSILON_PRVP 0.0001

class PRVEvaluator: public Evaluator<RepPRV, MemPRVP>
{
private:
	PRVPProblemInstance& pPRVP;

	// Your private vars

public:
	PRVEvaluator(PRVPProblemInstance& _pPRVP) : // If necessary, add more parameters
		pPRVP(_pPRVP)
	{
		// Put the rest of your code here
	}

	virtual ~PRVEvaluator()
	{

	}

	EvaluationPRV& evaluate(const RepPRV& rep)
	{

		//contando mais uma avaliação total feita
		aval++;
		MemPRVP mem(pPRVP.nCli + 1, pPRVP.nPeriod);

		double fo = 0; // Evaluation Function Value
		double inf = 0;

		int veiculos = rep.size();
		vector<double> aux_load(veiculos);
		for (int v = 0; v < veiculos; v++) //veiculos
		{
			int clientes = rep.at(v).size();
			if (clientes > 0)
			{
				double demanda_atendida = 0;
				fo += (*pPRVP.dist)(0, rep.at(v).at(0));

				for (int c = 0; c < clientes - 1; c++)
				{
					demanda_atendida += pPRVP.dados->at(rep.at(v).at(c)).at(DEMANDA);
					fo += (*pPRVP.dist)(rep.at(v).at(c), rep.at(v).at(c + 1));
				}
				fo += (*pPRVP.dist)(rep.at(v).at(clientes - 1), 0);
				demanda_atendida += pPRVP.dados->at(rep.at(v).back()).at(DEMANDA);

				//atualizando o load da memória
				aux_load.at(v) = demanda_atendida;

				inf += max(demanda_atendida - pPRVP.capacidade, 0.0);
				//cout<<"demanda "<<demanda_atendida<<" cap:"<<pPRVP.capacidade<<" \tinf:"<<inf<<endl;
			}
			else
				aux_load.at(v) = 0;
		}

		mem.getRouteLoad() = aux_load;

		//cout<<"%%%%inf:"<<inf<<endl;
		return *new EvaluationPRV(fo, inf * 10000, mem);
		//return *new EvaluationPRVP(fo, *new int);
	}

	void evaluate(EvaluationPRV& e, const RepPRV& rep)//todo verificar a avaliação sem memória -> leak
	{
		double fo = 0; // Evaluation Function Value
		double inf = 0;
		double pesoCapacidade = 10000;
		if (e.getM().getDelta() != 0 || e.getM().getDelta_inf() != 0)
		{
			//contando mais uma avaliação rápida feita
			avalrap++;
			//cout<<"avaliacao rapida: "<<e.getObjFunction()<< " + "<<e.getM().getDelta()<< "= "<<e.getObjFunction() + e.getM().getDelta()<<endl;
			//cout<<"avaliacao rapida inf: "<<e.getInfMeasure()<< " + "<<e.getM().getDelta_inf()<< "= "<<e.getInfMeasure() + e.getM().getDelta_inf()<<endl;
			//getchar();
			fo = e.getObjFunction() + e.getM().getDelta();
			inf = e.getInfMeasure() + e.getM().getDelta_inf() * pesoCapacidade;
		}
		else
		{
			//contando mais uma avaliação total feita
			aval++;

			int veiculos = rep.size();
			vector<double> aux_load(veiculos);
			for (int v = 0; v < veiculos; v++) //veiculos
			{
				int clientes = rep.at(v).size();
				if (clientes > 0)
				{
					double demanda_atendida = 0;
					fo += (*pPRVP.dist)(0, rep.at(v).at(0));

					for (int c = 0; c < clientes - 1; c++)
					{
						demanda_atendida += pPRVP.dados->at(rep.at(v).at(c)).at(DEMANDA);
						fo += (*pPRVP.dist)(rep.at(v).at(c), rep.at(v).at(c + 1));
					}
					fo += (*pPRVP.dist)(rep.at(v).at(clientes - 1), 0);
					demanda_atendida += pPRVP.dados->at(rep.at(v).back()).at(DEMANDA);

					//memoria
					aux_load.at(v) = demanda_atendida;

					inf += max(demanda_atendida - pPRVP.capacidade, 0.0);
					//cout<<"demanda "<<demanda_atendida<<" cap:"<<pPRVP.capacidade<<" \tinf:"<<inf<<endl;
				}
				else
					aux_load.at(v) = 0;
			}

			e.getM().getRouteLoad() = aux_load;

			inf = inf * pesoCapacidade;

		}

		e.getM().setDelta(0.0);
		e.getM().setDelta_inf(0.0);

		e.setObjFunction(fo);
		e.setInfMeasure(inf);

		//cout<<"%%%%fo:"<<fo<<endl;
		//cout<<"%%%%inf:"<<inf<<endl<<endl;

		//return *new EvaluationPRVP(fo, *new int);
	}

	virtual bool betterThan(double a, double b)
	{
		// MINIMIZATION
		return (a < (b - EPSILON_PRVP));
	}

};

#endif /*PRVP_EVALUATORPRV_HPP_*/

